﻿using System;
using System.Linq.Expressions;
using System.Windows;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Messaging;
using System.Windows.Input;
using GalaSoft.MvvmLight.Ioc;
using IkeCode.WP7.HQReader.Services;
using IkeCode.WP7.Toolkit.Base;
using IkeCode.WP7.Toolkit.Base.Navigation;
using GalaSoft.MvvmLight.Threading;
using IkeCode.WP7.Toolkit.Helpers;

namespace IkeCode.WP7.HQReader.Base
{
    /// <summary>
    /// Base class for ViewModels
    /// </summary>
    public abstract class BaseViewModel : ViewModelBase
    {
        #region ## Services ##

        /// <summary>
        /// IcLoadingService instance
        /// </summary>
        protected IcLoadingService _loadingService;
        /// <summary>
        /// INavigationService instance
        /// </summary>
        protected readonly INavigationService _navigationService;

        #endregion ## Services ##

        /// <summary>
        /// Default constructor
        /// </summary>
        public BaseViewModel()
        {
            this._loadingService = SimpleIoc.Default.GetInstance<IcLoadingService>();
            this._navigationService = SimpleIoc.Default.GetInstance<INavigationService>();
            Messenger.Default.Register<IcLoadingViewModel>(this, "LoadingSwitch", (model) =>
            {
                this.LoadingViewModel = model;
            });
        }

        #region ## Common Properties ##

        private string _pageTitle;
        /// <summary>
        /// Page Title, lower case by default
        /// </summary>
        public string PageTitle
        {
            get { return string.IsNullOrWhiteSpace(_pageTitle) ? "..." : _pageTitle.ToLower(); }
            set
            {
                if (_pageTitle == value)
                    return;

                _pageTitle = value;
                RaisePropertyChanged("PageTitle");
            }
        }

        private string _pagePrimaryTitle;
        /// <summary>
        /// Page Primary Title, return the application name by default.
        /// </summary>
        public string PagePrimaryTitle
        {
            get { return string.IsNullOrWhiteSpace(_pagePrimaryTitle) ? "iHQReader" : _pagePrimaryTitle; }
            set
            {
                if (_pagePrimaryTitle == value)
                    return;

                _pagePrimaryTitle = value;
                RaisePropertyChanged("PagePrimaryTitle");
            }
        }

        private IcLoadingViewModel _loadingViewModel;
        /// <summary>
        /// Loading control view model
        /// </summary>
        public IcLoadingViewModel LoadingViewModel
        {
            get { return _loadingViewModel; }
            private set
            {
                _loadingViewModel = value;
                RaisePropertyChanged("LoadingViewModel");
            }
        }

        /// <summary>
        /// Self Uri
        /// </summary>
        public abstract Uri MyUri { get; }

        #endregion ## Common Properties ##

        #region ## Protected Methods ##

        /// <summary>
        /// Dispatch action to Deployment thread 
        /// </summary>
        /// <param name="actionToInvoke">ACtion to be executed</param>
        protected void BeginInvoke(Action actionToInvoke)
        {
            DispatcherHelper.CheckBeginInvokeOnUI(actionToInvoke);
        }

        /// <summary>
        /// Dispatch to application property id changed
        /// </summary>
        /// <param name="propertyName">Property name</param>
        protected override void RaisePropertyChanged(string propertyName)
        {
            this.BeginInvoke(() =>
            {
                base.RaisePropertyChanged(propertyName);
            });
        }

        /// <summary>
        /// Dispatch to application property id changed
        /// </summary>
        /// <param name="propertyExpression">Property expression</param>
        /// <example>
        /// RaisePropertyChanged&lt;string&gt;(() => StringVar);
        /// </example>
        protected override void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)
        {
            this.BeginInvoke(() =>
            {
                base.RaisePropertyChanged<T>(propertyExpression);
            });
        }

        /// <summary>
        /// Used when other page affects any property of current page and need to be refreshed
        /// </summary>
        protected virtual void ReloadView()
        {

        }

        /// <summary>
        /// Register when view need to be reload by other view
        /// </summary>
        protected void RegisterReloadView<T>()
            where T : BaseViewModel
        {
            Messenger.Default.Register<T>(this, "Reload", (message) =>
            {
                this.ReloadView();
            });
        }

        /// <summary>
        /// Navigate to Page Uri, but before try to get instance of TTarget to ensure Messenger receive
        /// </summary>
        /// <typeparam name="TTarget">Target type, e.g.: ContosoViewModel</typeparam>
        protected void NavigateTo<TTarget>()
            where TTarget : BaseViewModel
        {
            var vmInstance = SimpleIoc.Default.GetInstance<TTarget>();
            var url = vmInstance.MyUri;

            _navigationService.NavigateTo(url);
        }

        /// <summary>
        /// UIThread message
        /// </summary>
        /// <param name="message">Message text</param>
        /// <param name="title">Message title</param>
        /// <param name="buttons">Buttons to be displayed</param>
        protected void ShowMessage(string message, string title, MessageBoxButton buttons)
        {
            this.BeginInvoke(() => { MessageBox.Show(message, title, buttons); });
        }

        /// <summary>
        /// UIThread message
        /// </summary>
        /// <param name="message">Message text</param>
        protected void ShowMessage(string message)
        {
            this.BeginInvoke(() => { MessageBox.Show(message); });
        }

        #endregion ## Protected Methods ##

        #region ## Common Commands ##

        /// <summary>
        /// Go back to last page
        /// </summary>
        public ICommand GoBack
        {
            get
            {
                return new RelayCommand((arg) =>
                {
                    _loadingService.LoadingSwitch(false);
                    _navigationService.GoBack();
                });
            }
        }

        /// <summary>
        /// Default edit command
        /// </summary>
        public virtual ICommand ManagerCommand
        {
            get
            {
                return new RelayCommand((param) =>
                {

                });
            }
        }

        /// <summary>
        /// Default pin or unpin command
        /// </summary>
        public virtual ICommand PinUnpinCommand
        {
            get
            {
                return new RelayCommand((param) =>
                {

                });
            }
        }

        /// <summary>
        /// Default remove command
        /// </summary>
        public virtual ICommand RemoveCommand
        {
            get
            {
                return new RelayCommand((param) =>
                {

                });
            }
        }

        /// <summary>
        /// Default reload command
        /// </summary>
        public virtual ICommand ReloadCommand
        {
            get
            {
                return new RelayCommand((param) =>
                {

                });
            }
        }

        #endregion ## Common Commands ##
    }
}